package com.xinyue.game.gateway.local;

import com.xinyue.cross.server.client.GameServerClientService;
import com.xinyue.cross.server.client.NotFundGameServerException;
import com.xinyue.cross.server.client.XinyueCrossClientConfig;
import com.xinyue.game.gateway.common.*;
import com.xinyue.game.message.GameServerMessageModel;
import com.xinyue.game.message.GameServerRequestHeader;
import com.xinyue.game.utils.GameServerUtil;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Service;

/**
 * 负责向网关后面的服务发送消息
 *
 * @author 王广帅
 * @since 2023/6/28 20:47
 **/
@Service
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class DispatcherRequestHandler extends ChannelInboundHandlerAdapter {

    private static Logger logger = LoggerFactory.getLogger(DispatcherRequestHandler.class);
    @Autowired
    private GameServerClientService gameServerClientService;
    @Autowired
    private GameGatewayConfig gameGatewayConfig;
    @Autowired
    private UserChannelService userChannelService;
    @Autowired
    private XinyueCrossClientConfig config;

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        userChannelService.addChannelContext(ctx);
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {

        if (msg instanceof GameServerMessageModel) {
            GameServerMessageModel<GameGatewayMessageRequestHeader> gatewayMessageWrapper = (GameServerMessageModel) msg;
            try {
                ByteBuf byteBuf = gatewayMessageWrapper.getBody();
                // 先读取一下包头
                GameGatewayMessageRequestHeader gameGatewayMessageHeader = gatewayMessageWrapper.getHeader();
                logger.debug("收到用户客户端消息：{}", gameGatewayMessageHeader);
                GameServerRequestHeader gameLogicMessageHeader = this.getGameLogicMessageHeader(ctx, gameGatewayMessageHeader);
                // 将新的包头和客户端发送的剩下的数据转发给网关后面的服务
                GameServerMessageModel<GameServerRequestHeader> msgModel = new GameServerMessageModel<>();
                msgModel.setHeader(gameLogicMessageHeader);
                msgModel.setBody(byteBuf);
                String playerId = userChannelService.getPlayerId(ctx);
                // 使用playerId作为Key，保证同一个用户的消息都在同一个队列中
                String serviceId = gameServerClientService.getServiceIdFromRequestUri(gameLogicMessageHeader.getRequestUri());
                gameServerClientService.sendMsg(playerId, serviceId, msgModel);
            } catch (Throwable e) {
                logger.error("网关异常", e);
                GameServerMessageModel<GameGatewayMessageResponseHeader> messageModel;
                if (e instanceof NotFundGameServerException) {
                    messageModel = GatewayResponseUtil.getResponseMessageModel(gatewayMessageWrapper, ServerErrorCode.NOT_FOUND_SERVER, "目标服务未启动或未注册到网关");
                } else {
                    messageModel = GatewayResponseUtil.getResponseMessageModel(gatewayMessageWrapper, ServerErrorCode.UNKNOWN_ERROR, e.getMessage());
                }
                ctx.writeAndFlush(messageModel);
            }
        } else {
            ctx.fireChannelRead(msg);
        }

    }

    private GameServerRequestHeader getGameLogicMessageHeader(ChannelHandlerContext ctx, GameGatewayMessageRequestHeader header) {
        GameServerRequestHeader logicHeader = new GameServerRequestHeader();
        String userKey = userChannelService.getPlayerId(ctx);
        if (userKey == null) {
            userKey = ctx.channel().id().asLongText();
        }
        String clientIp = GameServerUtil.getRemoteIP(ctx.channel());
        logicHeader.setClientIp(clientIp);
        logicHeader.setUserKey(userKey);
        logicHeader.setRequestId(header.getRequestId());
        logicHeader.setRequestUri(header.getRequestUri());
        logicHeader.setRequestTime(header.getRequestTime());
        logicHeader.setClientInstanceId(config.getClientInstanceId());
        logicHeader.setClientInstanceId(gameGatewayConfig.getGatewayNodeId());
        return logicHeader;
    }
}
